package com.zyg.lock;

import org.junit.Test;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.StampedLock;

public class MyStampedLockDemo {

    public ExecutorService executorService = Executors.newFixedThreadPool(100);

    @Test
    public void testReadAndWriteLock() {
        Point point = new Point(10.0, 20.0);
        //任务一：对数据进行写,获取写锁
        CompletableFuture.runAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(3);
                point.move(20.1, 20.2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //executorService.shutdown();
        }, executorService);
        //任务二:对数据进行读取，获取读锁
        CompletableFuture.runAsync(() -> {
            point.read();
            //executorService.shutdown();
        }, executorService);
        executorService.shutdown();
        System.out.println("main end");

//        for (int i = 0; i < 3; i++) {
//            CompletableFuture.runAsync(()->{
//                point.move(20.1,20.2);
//                //executorService.shutdown();
//            },executorService);
//        }
    }


}

class Point {
    private double x, y;
    private final StampedLock sl = new StampedLock();

    public Point() {
    }

    public Point(double x, double y) {
        this.x = x;
        this.y = y;
    }

    public double getX() {
        return x;
    }

    public void setX(double x) {
        this.x = x;
    }

    public double getY() {
        return y;
    }

    public void setY(double y) {
        this.y = y;
    }

    /**
     * 测试写锁
     *
     * @param deltaX
     * @param deltaY
     */
    void move(double deltaX, double deltaY) { // an exclusively locked method
        long stamp = sl.writeLock();
        try {
            x += deltaX;
            y += deltaY;
            System.out.println("x------->" + x);
            System.out.println("y------->" + y);
            System.out.println("当前线程--------->" + Thread.currentThread().getName());
        } finally {
            System.out.println("wrtieLock的票据为-----》" +stamp);
            sl.unlockWrite(stamp);
        }
    }

    void read() { // an exclusively locked method
        long stamp = sl.readLock();
        try {
            System.out.println("x------->" + x);
            System.out.println("y------->" + y);
            System.out.println("当前线程--------->" + Thread.currentThread().getName());
        } finally {
            System.out.println("readLock的票据为-----》" +stamp);
            sl.unlockRead(stamp);
        }
    }

    /**
     * 测试乐观读锁
     *
     * @return
     */
    double distanceFromOrigin() { // A read-only method
        long stamp = sl.tryOptimisticRead();
        double currentX = x, currentY = y;
        if (!sl.validate(stamp)) {
            stamp = sl.readLock();
            try {
                currentX = x;
                currentY = y;
            } finally {
                sl.unlockRead(stamp);
            }
        }
        return Math.sqrt(currentX * currentX + currentY * currentY);
    }

    /**
     * 测试读锁转化为写锁
     *
     * @param newX
     * @param newY
     */
    void moveIfAtOrigin(double newX, double newY) { // upgrade
        // Could instead start with optimistic, not read mode
        long stamp = sl.readLock();
        try {
            while (x == 0.0 && y == 0.0) {
                long ws = sl.tryConvertToWriteLock(stamp);
                if (ws != 0L) {
                    stamp = ws;
                    x = newX;
                    y = newY;
                    break;
                } else {
                    sl.unlockRead(stamp);
                    stamp = sl.writeLock();
                }
            }
        } finally {
            sl.unlock(stamp);
        }
    }
}
